/*
	Copyright Christopher Diggins 2008
	Licensed under LGPL version 3.0
	http://cppscript.googlecode.com
*/

#ifndef CPPI_HPP
#define CPPI_HPP

#include <cppscript>
#include <map>

#include "yard\include\yard.hpp"
#include "yard\grammars\yard_cppscript_grammar.hpp"
#include "sexpr.hpp"

typedef yard::Ast<>::AbstractNode Node;

namespace cppi
{
	using namespace cppscript_grammar;

	std::map<std::string, std::string> type_name_map;

	template<typename T>
	void AddTypeName(const std::string& x) {
		const std::type_info& ti = typeid(T);
		type_name_map[ti.name()] = x;
	}

	void InitializeTypeNameMap()
	{
		AddTypeName<Name>("name");
		AddTypeName<Arg>("arg");
		AddTypeName<Expr>("expr");
		AddTypeName<Literal>("literal");
		AddTypeName<ParanthesizedExpr>("paran_expr");
		AddTypeName<BracketedExpr>("bracket_expr");
		AddTypeName<SimpleExpr>("simple_expr");
		AddTypeName<VarInit>("var_init");
		AddTypeName<Statement>("statement");
		AddTypeName<CaseStatement>("case");
		AddTypeName<DefaultStatement>("default");
        AddTypeName<CodeBlock>("block");
        AddTypeName<VarDecl>("var_decl");
        AddTypeName<IfStatement>("if");
		AddTypeName<SwitchStatement>("switch");
		AddTypeName<ForEachStatement>("foreach");
		AddTypeName<ForStatement>("for");
		AddTypeName<WhileStatement>("foreach");
		AddTypeName<DoStatement>("do");
		AddTypeName<BreakStatement>("break");
		AddTypeName<ReturnStatement>("return");
		AddTypeName<ExprStatement>("expr_statement");
		AddTypeName<TryCatchStatement>("try_catch");
		AddTypeName<ThrowStatement>("throw");
		AddTypeName<EmptyStatement>("noop");
		AddTypeName<ArgList>("args");
		AddTypeName<IncludeTarget>("include");
		AddTypeName<Function>("function");
		AddTypeName<void>("ast");
	}

	std::string NodeName(Node* node) {
		const char* name = node->GetRuleTypeInfo().name();
		assert(type_name_map.find(name) != type_name_map.end());
		return type_name_map[name];
	}

	var ShouldStoreContent(var name) {
		return (name == "name") 
			|| (name == "simple_expr")
			|| (name == "literal");
	}

	var YardNodeToAst(Node* node) {
		var r = list();
		std::string name = NodeName(node);
		r.push_back(name);
		for (Node* child = node->GetFirstChild(); child != NULL; child = child->GetSibling())
			r.push_back(YardNodeToAst(child));

		if (ShouldStoreContent(name)) {
			std::string content(node->Begin(), node->End());
			r.push_back(content.c_str());
		}

		return r;
	}

	template<typename Rule_T>
	bool Parse(const char* input, const char* end, var& tree, bool verbose = true) {
		InitializeTypeNameMap();
		SimpleTextParser parser(input, end);
		bool r = parser.Parse<Rule_T>();
		if (!r && verbose) {
			parser.OutputLocation();
		}
		else {
			tree = YardNodeToAst(parser.GetAstRoot());
		}
		return r;
	};

	bool ParseScript(const char* input, const char* end, var& tree, bool verbose = true) {
		return Parse<cppscript_grammar::Script>(input, end, tree, verbose);
	}
}

#endif
